﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using QLab.UX.Utilities;

namespace QLab.UX.Engine
{
    internal class XMLManager
    {
        private static XMLManager instance = null;
        public static XMLManager Instance
        {
            get
            {
                if (XMLManager.instance == null)
                    XMLManager.instance = new XMLManager();
                return XMLManager.instance;
            }
        }

        private XMLManager()
        {
            
        }
 
        public QLabSolution LoadSolution(string filename)
        {
            QLabSolution solution = null; 
            XmlTextReader reader = new XmlTextReader(filename);

            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.EndElement) continue;

                reader.MoveToContent();
                Dictionary<string, string> atributes = new Dictionary<string, string>();
                if (reader.MoveToFirstAttribute())
                    do
                    {
                        atributes.Add(reader.Name, reader.Value);
                    } while (reader.MoveToNextAttribute());
                reader.MoveToElement();

                if (reader.Name == "Solution")
                    solution = new QLabSolution(Directory.GetParent(filename).FullName, atributes["Name"]);
                else if (reader.Name == "Project")
                {
                    string path = string.Empty;

                    if (Path.IsPathRooted(atributes["Path"]))
                        path = atributes["Path"];
                    else path = solution.HomeFolderPath + atributes["Path"];

                    QLabProject project = this.LoadProject(path + atributes["Name"], solution);
                    solution.Projects.Add(project.Name, project);
                }
            }
            reader.Close();
            return solution;
        }

        private QLabProject LoadProject(string pathToFile, QLabSolution parentSolution)
        {
            XmlTextReader reader = new XmlTextReader(pathToFile);
            QLabProject project = null;
            QLabFolder activeFolder = null;
            int activeFolderDepth = 0;

            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.EndElement)
                {
                    if (reader.Name == "Folder")
                    {
                        activeFolder = activeFolder.ParentFolder;
                        activeFolderDepth--;
                    }
                    continue;
                }

                Dictionary<string, string> atributes = new Dictionary<string, string>();
                reader.MoveToContent();
                if (reader.MoveToFirstAttribute())
                    do
                    {
                        atributes.Add(reader.Name, reader.Value);
                    } while (reader.MoveToNextAttribute());
                reader.MoveToElement();

                if (reader.Name == "Project")
                {
                    bool active = Convert.ToBoolean(atributes["Active"]);

                    project = new QLabProject(Directory.GetParent(pathToFile).FullName,
                        atributes["Name"], parentSolution, active);
                    if (active)
                        SolutionManager.Instance.ActiveFolder = project.Folder;

                    activeFolder = project.Folder;
                    activeFolderDepth = reader.Depth;
                }
                else if (reader.Name == "Folder")
                {
                    #region read folder
                    QLabFolder folder = null;
                    if (reader.Depth > activeFolderDepth)
                    {
                        bool active = Convert.ToBoolean(atributes["Active"]);
                        folder = new QLabFolder(activeFolder, project, atributes["Name"], active);
                        if(active)
                            SolutionManager.Instance.ActiveFolder = folder;
                        activeFolder.QLabFolders.Add(folder.Name, folder);
                    }
                    else if (reader.Depth == activeFolderDepth)
                    {
                        throw new Exception();
                    }
                    else if (reader.Depth < activeFolderDepth)
                    {
                        throw new Exception();
                    }
                    activeFolder = folder;
                    activeFolderDepth = reader.Depth;

                    if (reader.IsEmptyElement)
                    {
                        activeFolder = folder.ParentFolder;
                        activeFolderDepth--;
                    }
                    #endregion
                }
                else if (reader.Name == "File")
                {
                    #region read file
                    QLabFunction file = null;
                    if (reader.Depth > activeFolderDepth)
                    {
                        file = new QLabFunction(activeFolder, project, atributes["Name"]);
                        activeFolder.QLabFiles.Add(file.Name, file);
                    }
                    else if (reader.Depth == activeFolderDepth)
                    {
                        throw new Exception();
                    }
                    else if (reader.Depth < activeFolderDepth)
                    {
                        throw new Exception();
                    }
                    #endregion
                }
            }
            reader.Close();
            return project;
        }

        public void SaveSolution(QLabSolution qLabSolution)
        {
            if (!Directory.Exists(qLabSolution.HomeFolderPath))
                Directory.CreateDirectory(qLabSolution.HomeFolderPath);

            XmlWriter solutionWriter = new XmlTextWriter(qLabSolution.HomeFolderPath + qLabSolution.File, Encoding.Default);

            solutionWriter.WriteStartDocument();
            solutionWriter.WriteStartElement("Solution");
            solutionWriter.WriteAttributeString("Name", qLabSolution.Name);

            foreach (QLabProject item in qLabSolution.Projects.Values)
            {
                solutionWriter.WriteStartElement("Project");
                solutionWriter.WriteAttributeString("Path", PathHelper.Instance.RelativePath(qLabSolution.HomeFolderPath, item.HomeFolderPath));
                solutionWriter.WriteAttributeString("Name", item.File);
                solutionWriter.WriteEndElement();

                this.SaveProject(item);
            }

            solutionWriter.WriteEndDocument();
            solutionWriter.Close();
        }

        private void SaveProject(QLabProject qLabProject)
        {
            if (!Directory.Exists(qLabProject.HomeFolderPath))
                Directory.CreateDirectory(qLabProject.HomeFolderPath);

            XmlWriter projectWriter = new XmlTextWriter(qLabProject.HomeFolderPath + qLabProject.File, Encoding.Default);
            projectWriter.WriteStartDocument();
            projectWriter.WriteStartElement("Project");
            projectWriter.WriteAttributeString("Name", qLabProject.Name);
            projectWriter.WriteAttributeString("Active", qLabProject.Folder.Active.ToString());

            this.WriteContainingFilesAndFolders(qLabProject.Folder, projectWriter);

            projectWriter.WriteEndDocument();
            projectWriter.Close();
        }

        private void WriteFolder(QLabFolder qLabFolder, XmlWriter projectWriter)
        {
            projectWriter.WriteStartElement("Folder");
            projectWriter.WriteAttributeString("Name", qLabFolder.Name);
            projectWriter.WriteAttributeString("Active", qLabFolder.Active.ToString());

            this.WriteContainingFilesAndFolders(qLabFolder, projectWriter);

            projectWriter.WriteEndElement();
        }

        private void WriteContainingFilesAndFolders(QLabFolder qLabFolder, XmlWriter projectWriter)
        {
            foreach (QLabFolder folder in qLabFolder.QLabFolders.Values)
            {
                this.WriteFolder(folder, projectWriter);
            }
            foreach (QLabFunction file in qLabFolder.QLabFiles.Values)
            {
                projectWriter.WriteStartElement("File");
                projectWriter.WriteAttributeString("Name", file.Name);
                projectWriter.WriteEndElement();
            }
        }
    }
}
